/**
* @file		Area.ixx
* @brief	多个格子组成的区域
*
*
* @version	1.0
* @author	lveyou
* @date		22-06-02
*
* @note		分类：行政、河流、湖泊、山脉
* @note		同类之间应该是不能重复的
*/
export module Area;

import DND;
import Common;
import DefVar;
import DefOrder;
import ResMgr;
import Node;

//! 表示一个区域
export class Area
{
public:
	enum Refresh
	{
		AREA	= 1,
		NAME	= 2,
		ALL		= AREA | NAME,
	};

	enum Type : size_t
	{
		ADMIN,//行政
		GEO,//地理
	};

	struct SL
	{
		size_t _uid;
		size_t _idColor;//颜色id
		size_t _type;//类别

		string _name;//名字
		//拥有的节点
		Hash2D<zahlen, Node*> _allNode;

		void Save(StreamOutput& s);

		void Load(Area* area, StreamInput& s);
	};

	struct TP
	{
		//区域形成的范围，都是闭区间（只在刷新界面后有效）
		Point _xyLT;
		Point _xyRB;
	};

	struct UI
	{
		vector<gcSprite> _allSpr;
		Text* _txtName;
	};

public:
	Area(size_t uid)
	{
		_sl._uid = uid;
		_sl._idColor = 0;

		_ui._txtName = g_res->CreateTextArea();
	}

	Area(StreamInput& s)
	{
		_sl.Load(this, s);

		_ui._txtName = g_res->CreateTextArea();
	}

	void Render(real scale);

	//! 成功添加后（会替换区域所属） 需要刷新界面
	[[nodiscard]]
	bool Add(const Point& xy, bool replace);

	//! 成功移除后（会设置区域所属为-1） 需要刷新界面
	[[nodiscard]]
	bool Remove(const Point& xy);

	void RefreshUI(Refresh type);

	bool IsPickup()
	{
		return Any::Yes(_ui._allSpr, [](gcSprite spr) {
				return spr->IsPickup();
			});
	}

	//! 返回sl
	const SL& GetSL() { return _sl; }
	SL& GetSlRef() { return _sl; }

	//! 返回uid
	size_t GetUID() { return _sl._uid; }

	//! 返回名字，玩家所见
	string_view GetName() { return lang("area", _sl._name); }

	void Save(StreamOutput& s)
	{
		_sl.Save(s);
	}
private:
	SL _sl;
	TP _tp;
	UI _ui;
};

module: private;

void Area::SL::Save(StreamOutput& s)
{
	s.Write64(&_uid);
	s.Write64(&_idColor);
	s.Write(&_name);
	size_t size_y = _allNode.GetYSize();
	s.Write64(&size_y);
	for (auto& iter : _allNode.GetContainer())
	{
		s.Write64(&iter.first);//写入y值
		size_t size_x = iter.second.size();
		s.Write64(&size_x);//写入数量
		for (auto& iter1 : iter.second)
		{
			s.Write64(&iter1.first);
		}
	}
}

void Area::SL::Load(Area* area, StreamInput& s)
{
	s.Read64(&_uid);
	s.Read64(&_idColor);
	s.Read(&_name);
	size_t size_y;
	s.Read64(&size_y);

	for (size_t j = 0; j < size_y; ++j)
	{
		zahlen y;
		s.Read64(&y);//读取y值
		auto& iter = _allNode.GetContainer()[y];

		size_t size_x;
		s.Read64(&size_x);//读取数量
		for (size_t i = 0; i < size_x; ++i)
		{
			zahlen x;
			s.Read64(&x);

			auto iter1 = iter.insert({x, nullptr});
			assert(iter1.second);
		}
	}
}

void Area::Render(real scale)
{
	for (auto& iter : _ui._allSpr)
	{
		iter->Render();
	}

	if (scale < 0.06)
		return;

	if (scale <= 0.1)
	{
		_ui._txtName->SetFontSize(16);
	}
	else
	{
		_ui._txtName->SetFontSize(30);
	}

	//设置txtName位置（居中）
	Point xy_center = (_tp._xyLT + _tp._xyRB) / 2_z;
	Vector2 pos = Common::WorldXy2WindowCenter(xy_center);
	_ui._txtName->SetCenter(pos);
	_ui._txtName->Render();
}

bool Area::Add(const Point& xy, bool replace)
{
	Node* node = Common::GetNode(xy);
	if (node == nullptr)
		return false;//节点不存在

	Node::TP& tp = node->GetTpRef();
	if (tp._uidArea == _sl._uid)
		return false;//已经属于自己

	if (tp._uidArea == -1
		|| replace)
	{//节点还未属于任何节点 或者 可以替换
		if (_sl._allNode.Add(xy, node))
		{
			if (tp._uidArea != -1)
			{//从其他 区域 移除节点，并 刷新 界面
				Area* area_other = Common::GetArea(tp._uidArea);
				assert(area_other);
				if (area_other->Remove(xy))
					area_other->RefreshUI(AREA);
				else
					assert(0);
			}
			tp._uidArea = _sl._uid;
			return true;
		}
		else
			return false;
	}
	return false;
}

bool Area::Remove(const Point& xy)
{
	if (_sl._allNode.Delete(xy))
	{
		Node* node = Common::GetNode(xy);
		assert(node);
		Node::TP& tp = node->GetTpRef();
		assert(tp._uidArea == _sl._uid);
		tp._uidArea = -1;
		return true;
	}
	return false;
}

void Area::RefreshUI(Refresh type)
{
	if (type & Refresh::AREA)
	{
		_ui._allSpr.clear();
		//每一行生成 1-N 个精灵
		if (_sl._allNode.IsEmpty())
		{//没有元素直接结束
			return;
		}

		struct Line
		{
			zahlen _y;
			zahlen _x0;
			zahlen _x1;//不包含x1
		};
		//生成的信息 y, x0, x1
		vector<Line> all_line;
		//
		for (auto& iter : _sl._allNode.GetContainer())
		{
			zahlen y_cur = iter.first;
			auto& line_y = iter.second;

			//有y则必存在元素
			assert(!line_y.empty());

			//不同一行，必然产生新行，设置此行初始状态
			zahlen x_beg = iter.second.begin()->first;
			zahlen x_end = x_beg;

			for (auto iter1 = line_y.begin(); iter1 != line_y.end();)
			{
				zahlen x_cur = iter1->first;

				if (x_cur != x_end)
				{//x不连续，生成一个rect，再设置状态
					all_line.push_back({ y_cur, x_beg, x_end });
					x_beg = x_cur;
					x_end = x_beg;
					//x_cur此时不应该前进
				}
				else
				{//是上一个的尾部
					++x_end;
					++iter1;
				}
			}
			//结束仍需处理
			if (x_beg != x_end)
			{
				all_line.push_back({ y_cur, x_beg, x_end });
			}
		}
		//生成spr
		Color color = g_factory->GetColor(format("area_{}", _sl._idColor));
		size_t i = 0;
		for (auto& iter : all_line)
		{
			Color col = createColor(color, 0.75f);
			gcSprite spr = g_factory->CreateSpriteDefault(col);
			spr->SetOrder(DefOrder::AREA);
			spr->SetCoor(Common::GetWorldCoor());

			Vector2 size = Vector2{ (iter._x1 - iter._x0) * DefVar::NODE_PIXEL, DefVar::NODE_PIXEL };
			Vector2 pos = Vector2{ iter._x0 * DefVar::NODE_PIXEL, iter._y * DefVar::NODE_PIXEL };

			spr->SetQuad(createQuad(size, false) + pos);
			_ui._allSpr.push_back(spr);
			++i;
		}

		//范围信息生成
		Numeric::Max(_tp._xyLT);
		Numeric::Min(_tp._xyRB);

		for (auto& iter : _sl._allNode.GetContainer())
		{
			zahlen y_cur = iter.first;
			_tp._xyLT[1] = min(_tp._xyLT[1], y_cur);
			_tp._xyRB[1] = max(_tp._xyRB[1], y_cur);
			for (auto& iter1 : iter.second)
			{
				zahlen x_cur = iter1.first; 
				_tp._xyLT[0] = min(_tp._xyLT[0], x_cur);
				_tp._xyRB[0] = max(_tp._xyRB[0], x_cur);
			}
		}
	}
	if (type & Refresh::NAME)
	{
		_ui._txtName->SetString(GetName());
	}
}


